<?php

require_once 'SimpleTableModel.class.php';

class SimpleTableObject {
	
	/**
	 * Model (from Database) of the specified SimpleTable
	 *
	 * @var SimpleTableModel
	 */
	private $tableModel;
	
	/**
	 * XML complete XML Modell
	 *
	 * @var SimpleXMLElement
	 */
	private $tableXML;
	private $tableView;
	private $tableHtml;
	
	private $tableRows;
	private $dataPath;
	private $pkSimpleTable;
	
	private $maxRowId;
	
	public function __construct() {
		
	}
	
	public function setDataPath($path) {
		$this->dataPath = $path;
	}
	public function getDataPath() {
		return $this->dataPath;
	}
	
	/**
	 * Loads the Table Metainformation from Database, no Data is beeing loaded
	 *
	 * @param int $pkSimpleTable
	 */
	public function loadTable($pkSimpleTable) {
		
		$this->pkSimpleTable = $pkSimpleTable;
		
		$this->tableModel = new SimpleTableItem($pkSimpleTable);
		
	}
	

	# FRONTEND FUNCTIONS #
	# ================== #	

	public function attachView(SimpleTableViewItem $view) {
		$this->tableView = $view;
	}
	
	/**
	 * Renders the Table to HTML usign the given View
	 * Two ways to render a table are available:
	 * - Render with Smarty or any other Template engine
	 * - Transform the XML via an XML-Transformation
	 *
	 */
	
	public function render() {

		if($this->tableView->displayMode=="template") {
			//Load Table Data
			$this->loadTableData();
			if($this->tableView->presort) {
				$this->sortIntenal($this->tableView->presort);
			}
			$cfg = Runtime::getConfiguration();
			
			$smarty = new Smarty();
			$smarty->compile_dir = $cfg["paths"]["tmp"] . "/cache/smarty";
			$smarty->plugins_dir = eCMS_DIR . "/app/lib/smarty/plugins";
			
			$smarty->assign("Table_Rows", $this->getRows());
			$smarty->assign("Table_Columns", $this->getColumns());
			$smarty->assign("Sys_CurrentUser", SecurityUser::getUser());
			
			//JS Libs-Path
			$smarty->assign("Sys_JsLibsURL", $cfg['JsLibsURL']);
						
			$tplfile = $this->dataPath . "/../views/" . $this->tableView->sysname . ".tpl.php";
			if(file_exists($tplfile)) {
				$this->tableHtml = $smarty->fetch($tplfile);
				return true;	
			}
			else {
				//echo $tplfile;
				return false;
			}
									
		}
		else {
			
			//Process xml with XMLST-File
		}
		
	}
	
	/**
	 * Returns the HTML-Code wich was rendered bevore by calling the render()-function
	 * @return string
	 */
	public function getHTML() {
		return $this->tableHtml;
	}

	# BACKEND FUNCTIONS #
	# ================= #
	
	/**
	 * Loads the Data an processes it as it defined in the definition of the cols
	 * Used to display Data inside the Backend. Its completly independent from the front-end rendering
	 *
	 */		
	
	public function load() {
		$this->loadTableData();
		
		//Sort as defined as internalSort in the table;
		$this->sortIntenal($this->tableModel->basicSort);
		
	}
	
	public function save() {

		//Save Table Definitions
		
		//Save Table Data
		return $this->saveTableData();
		
	}
	
	public function getName() {
		return $this->tableModel->name;
	}
	
	public function getSecurityObject() {
		
		return $this->tableModel->getSecurityObject();
	}
	/**
	 * Returns the Table-Structure
	 *
	 * @return SimpleTableItem
	 */
	public function getTableModel() {
		return $this->tableModel;
	}
	
	public function getColumns() {
		return $this->tableModel->columns;
	}
	
	public function getRows() {
		return $this->tableRows;
	}
	/**
	 * Enter description here...
	 *
	 * @param int $rowId
	 * @return SimpleTableRow
	 */	
	public function getRow($rowId) {

		foreach ($this->getRows() as $row) {
			if($row->getId() == $rowId) {
				return $row;			
			}
		}
		return null;
	}
	
	public function deleteRow($id) {
		
		if($this->maxRowId==0) { $this->loadTableData(); }
		for($i=0;$i<sizeof($this->tableRows);$i++) {
			if($this->tableRows[$i]->getId()==$id) {
				
				$this->tableRows[$i]->deleteValues();
				unset($this->tableRows[$i]);
			}
		}
	}
	
	public function addRow() {
		
		if($this->maxRowId==0) { $this->loadTableData(); }
		
		$row = new SimpleTableRow(null);
		$row->setId($this->maxRowId+1);
		$row->setSimpleTableObject($this);
		
		//Go through the Columns in the Column definition
		foreach ($this->getColumns() as $col) {
			
			$c = new SimpleTableCell(null, $col);
			$c->setRow($row);
			$row->addCell($c);
		}

		
		array_push($this->tableRows, $row);
		
		return $row;
	}
	

	public function emptyTable() {
		
		$this->tableRows = null;
		
	}
	
	
	# INTERNAL FUNCTIONS #
	# ================== #                              
	
	private function loadXML() {
		
		//$this->dataPath.= "/" . sprintf("%05s", $this->pkSimpleTable);
		
		$file = $this->dataPath . "/table.xml"; 
		if(file_exists($file)) {
			$xml = simplexml_load_file($file);
			$this->tableXML = $xml->tabledata;
		}
		else {
			$this->tableXML = null;
		}
		
		
	}
	
	private function saveXML() {
		
		$content = $this->tableXML->asXML();
		if(file_put_contents($this->dataPath . "/table.xml", $content)) {
			return true;
		}
		else {
			return false;
		}
		
	}
	/**
	 * The Table Data is loaded into this class
	 *
	 */
	private function loadTableData() {

		$this->loadXML();
		
		if($this->tableXML) {
		
			//Stores the RowData
			$this->tableRows = array();
			
			//Load Rows from XML to Internal Array
			
			foreach ($this->tableXML->row as $XMLrow) {
				
				
				//Create New SimpleTableRow
				$row = new SimpleTableRow($XMLrow);
				$row->setSimpleTableObject($this);
				
				//Go through the Columns in the Column definition
				foreach ($this->getColumns() as $col) {
					
					$xmlCell = $XMLrow->{$col->name};
					$c = new SimpleTableCell($xmlCell, $col);
					$c->setRow($row);
					$row->addCell($c);
				}
	
				array_push($this->tableRows, $row);
				
				//Determine highest rowId
				if(is_numeric($row->getId()) && $row->getId() > $this->maxRowId) { $this->maxRowId = $row->getId(); }
	
			}
		}
		
	}
	
	private function saveTableData(){
		
		$this->tableXML = new SimpleXMLElement("<xml></xml>");
		$tableData = $this->tableXML->addChild("tabledata");
		
		foreach ($this->tableRows as $row) {
			echo $row->getId()."<br>";
			//Save changes
			$row->save();
			$xmlRow = $tableData->addChild("row");
			$xmlRow->addAttribute("id", $row->getId());
			$xmlRow->addAttribute("createDate", $row->getCreateDate());
			$xmlRow->addAttribute("fkCreateUser", $row->getFkCreateUser());
			
			foreach ($row->getCells() as $cell) {
				
				$xmlCell = $xmlRow->addChild($cell->getName(), utf8_encode(addslashes(htmlspecialchars($cell->getValue()))));
				if($cell->getChangeDate()) $xmlCell->addAttribute("changeDate", $cell->getChangeDate());
				if($cell->getFkChangeUser()) $xmlCell->addAttribute("fkChangeUser", $cell->getFkChangeUser());
			}
		}
		
		return $this->saveXML();
		
	}
	
	private function sortIntenal($sorting) {
		
		if($this->tableRows) {
			
			$columns = split(";", $sorting);
			
			foreach ($columns as $col) {
				
				list($field, $direction) = split(" ", $col);
				if($field && $direction) {
					$so = new MultiSortOrder($field, $direction, "attrib");
					MultiSorter::addOrderBy($so);
											
				}
			}
			
			$this->tableRows =  MultiSorter::sort($this->tableRows);
		}
		
	}
		
	
}

class SimpleTableRow {
	/**
	 * Contains an Array of all Cells in this Row
	 *
	 * @var SimpleTableCell[]
	 */
	
	private $id;
	private $fkCreateUser;
	private $fkCreateUserName;
	private $createDate;
	private $isNew;
	/**
	 * 	
	 *
	 * @var SimpleTableCell[]
	 */
	private $cells;
	
	/**
	 * Enter description here...
	 *
	 * @var SimpleXMLElement
	 */
	//private $xmlData;
	/**
	 * References to the current SimpleTableObject containing this Row
	 *
	 * @var SimpleTableObject
	 */
	private $simpleTableObject;
	
	public function __construct($xmlRow) {
		
		//$this->xmlData = $xmlRow;
		if($xmlRow) { 
			$this->id = sprintf($xmlRow["id"]);
			$this->fkCreateUser = sprintf($xmlRow["fkCreateUser"]);
			$this->createDate = sprintf($xmlRow["createDate"]);
		}
		else {
			
			$this->fkCreateUser = Runtime::getCurrentUser()->getPkSecurityUser();
			$this->createDate = date("Y-m-d H:i:s");
			$this->isNew = true;
		}
		
		$this->cells = array();
		
	}
	
	public function save() {
		
		//$i = 0;
		//$this->xmlData = new SimpleXMLElement("<row></row>");
		
		foreach ($this->cells as $c) {
			
			$c->save();
			//$this->xmlData->addChild($c->getName(), $xml);

			//$i++;
		}
		
		//echo $this->xmlData->asXML();
	}
	
	public function setSimpleTableObject(SimpleTableObject $o) {
		$this->simpleTableObject = $o;
	}
	/**
	 * Returns the simpleTableObject
	 *
	 * @return SimpleTableObject
	 */
	public function getSimpleTableObject() { return $this->simpleTableObject; }
	
	public function addCell(SimpleTableCell $c) {
		
		$this->cells[$c->getName()] = $c;
		
		//array_push($this->cells, $c);
	}
	
	public function getCells() {
		return $this->cells;
	}
	
	public function getId() { return $this->id; }
	public function setId($value) { $this->id = $value; }
	
	public function getIsNew() { return $this->isNew; }
	
	public function getCell($name) {
		
		if(array_key_exists($name, $this->cells)) {
			return $this->cells[$name];
		}
		return null;
	}
	
	public function setValue($name, $value) {
	
		$c = $this->getCell($name);
		if($c) { $c->setValue($value); }
	}
	
	public function getCreateDate() { return $this->createDate; }
	public function getFkCreateUser() { return $this->fkCreateUser; }
	
	public function __get($name) { return $this->getCell($name); }
	
	public function deleteValues($colum=null) {
		
		$columns = array();
		
		if($colum==null) {
			$columns = $this->getCells();
		}
		else {
			$columns[0] = $this->getCell($colum);
		}
		
		foreach ($columns as $colum) {
			$colum->deleteValue();
		}
		
		
		
	}
	
	
}

class SimpleTableCell {
	
	private $name;
	private $value;
	private $type;
	private $lenght;
	
	private $fkChangeUser;
	private $fkChangeUserName;
	private $changeDate;
	
	private $isDirty;
	
	/**
	 * Enter description here...
	 *
	 * @var SimpleXMLElement
	 */
	//private $xmlData;
	
	/**
	 * SimpleTableRow reference
	 *
	 * @var SimpleTableRow
	 */
	private $row;
	
	
	public function __construct(SimpleXMLElement $xmlCell = null, SimpleTableColItem $col) {
		
		//$this->xmlData = $xmlCell;
		
		
		//Copy Values of xmlCell to own structure
		$this->value = str_replace("\\", "", utf8_decode(sprintf($xmlCell)));
		$this->fkChangeUser = sprintf($xmlCell["fkChangeUser"]);
		$this->changeDate = sprintf($xmlCell["changeDate"]);
		
		$this->lenght = $col->lenght;
		$this->name = $col->name;
		$this->type = $col->type;
		
	}
	
	function setRow(SimpleTableRow $r) {
		$this->row = $r;
	}
	
	function setColumn(SimpleTableColItem $c) {
		$this->column = $c;
	}
	
	public function getName() { return $this->name; }
	
	function getChangeDate() { return $this->changeDate; }
	function getFkChangeUser() { return $this->fkChangeUser; }
	
	public function __toString() {
		return $this->value;
	}
	
	public function getValue() {
		return $this->value;
	}
	
	public function setValue($v) {

		if($this->type=="image" && is_object($v)) {
			//Try to open as image
			$a = getimagesize($v->getTmpPath());
			if ($a[2] == 0) { 
				$v = $this->value; // Reset 
				echo "Sorry no image";
			}
			else {
			}
		}
			
		$this->isDirty = $this->value != $v;
		$this->value = $v;
	}
	
	public function save() {
		
		if($this->isDirty) {
			
			if(!$this->row->getIsNew()) {
				$this->changeDate = date("Y-m-d H:i:s");
				$this->fkChangeUser = Runtime::getCurrentUser()->getPkSecurityUser();
			}
						
			//Copy files if type is file oder image
			if(is_object($this->value) &&  $this->type == "image" || $this->type == "file") {
				
				$fileObj = $this->value;
				
				$path = $this->row->getSimpleTableObject()->getDataPath();
				$file = $path . "/files/" . $this->getFileName();
			
				
				if($this->type=="image") {
					
					$this->value = $fileObj->getFileName();
					$fileObj->copyTo($file . ".orig");
					
					//Check if it has to be resized
					if($this->lenght) { list($width, $height) = split("x", $this->lenght); }
					if($width > 0 && $height==0) { $height = $width * $width; /*Set imaginary width */ }
					if($height > 0 && $width==0) { $width = $height * $height; /*Set imaginary width */ }
					
					if($width > 0 && $height > 0) {
						Utils::resizeImage($file . ".orig", $file, $width, $height);
						echo "resized";
					}
					else {
						copy($file.".orig", $file);
					}
				}
				else {
					$fileObj->copyTo($file);
					$this->value = $fileObj->getFileName();
				}
			}
			
			//Save Values to the XML
			/*
			$this->xmlData = new SimpleXMLElement("<".$this->name . ">".$this->value."</".$this->name.">");
			$this->xmlData->addAttribute("changeDate", $this->changeDate);
			$this->xmlData->addAttribute("fkChangeUser", $this->fkChangeUser);
			*/
		}
		return $this->xmlData;
		
	}
	
	public function deleteValue() {
		if($this->type == "image" || $this->type=="file") {
			//Delete Files
			$path = $this->row->getSimpleTableObject()->getDataPath();
			$file = $path . "/files/" . $this->getFileName();
			
			@unlink($file . ".orig");
			@unlink($file);
			
		}
		
		$this->setValue(null);
	}
	
	public function getFileSize() {

		if($this->type=="image" || $this->type=="file") {
			
			$path = $this->row->getSimpleTableObject()->getDataPath();
			$file = $path . "/files/" . $this->getFileName();
			if(file_exists($file)) {
				return filesize($file);
			}
		}

		return -1;
	}

	public function getFileSizeName() {
		$size = $this->getFileSize();

		if($size > 1024*1024*1024) { return round($size / 1024 / 1024 / 1024, 2) . " GB"; }
		if($size > 1024*1024) { return round($size / 1024 / 1024, 2) . " MB"; }
		if($size > 1024) { return round($size / 1024, 2) . " KB"; }
		
		return $size . " Bytes";
	}
	
	public function getFileData() {
		
		if($this->type=="image" || $this->type=="file") {
			
			$path = $this->row->getSimpleTableObject()->getDataPath();
			$file = $path . "/files/" . $this->getFileName();
			if(file_exists($file)) {
				return file_get_contents($file);
			}
		}
		
		return null;
	}
	
	public function getFileName() {
		return md5($this->row->getId() . "_" . $this->name) . ".dat";
	}
	
	//Returns a hash with wich the id can be checked
	public function getDownloadHash() {
		return md5($this->getName()."_".$this->getFileSize());
	}
	
}
?>